#pragma once

#include "PushHandle.h"

struct FixInfo
{
	std::string wtfs;
	std::string node;
	int sysId;
	int nodeId;
	std::string token;
};

class DDRequest
{
public:
	DDRequest(HANDLE_CONN conn)
	{
		m_Conn = conn;
		m_Session = Fix_AllocateSession(conn);
		m_Params = make_unique<map<int, string>>();
	}

	~DDRequest()
	{
		Fix_ReleaseSession(m_Session);
	}

	void Init(const char *funcid, const FixInfo &info)
	{
		Fix_SetWTFS(m_Session, info.wtfs.c_str());
		Fix_SetNode(m_Session, info.node.c_str());
		Fix_SetToken(m_Session, info.token.c_str());
		Fix_SetSystemId(m_Session, info.sysId);
		Fix_SetNodeId(m_Session, info.nodeId);
		// Fix_CreateReq(m_Session, funcid.data());
		Fix_CreateHead(m_Session, funcid);
		m_Funcid = funcid;
	}

	void AddParam(int fidId, const string &fidVal)
	{
		m_Params->emplace(fidId, fidVal);
	}

	bool SendAndRecv()
	{
		if (!SetDDParams())
			return false;

		do
		{
			if (!Fix_Run(m_Session))
			{
				FIX_INT64 errcode = Fix_GetCode(m_Session);
				char errs[256]{};
				int errlen = sizeof(errs);
				Fix_GetErrMsg(m_Session, errs, errlen);
				fmt::print(fg(fmt::color::red), "Fix_Run 失败: {}, {}\n", errcode, errs);
				logger->warn("Fix_Run 失败: {}, {}\n", errcode, errs);
				return false;
			}

			auto errinfo = ParseError();
			if (!errinfo.empty())
			{
				fmt::print(fg(fmt::color::light_golden_rod_yellow), "业务请求失败：{}\n", errinfo);
				logger->warn("业务请求失败：{}", errinfo);
				return false;
			}

			int recCount = Fix_GetCount(m_Session);
			RecvAnswers(recCount);

			if (!IsNeedNext(recCount))
				break;
		} while (true);

		return true;
	}

	bool AsyncSend()
	{
		if (!SetDDParams())
			return false;

		if (!Fix_AsyncRun(m_Session))
		{
			FIX_INT64 errcode = Fix_GetCode(m_Session);
			char errs[256]{};
			int errlen = sizeof(errs);
			Fix_GetErrMsg(m_Session, errs, errlen);
			fmt::print(fg(fmt::color::red), "Fix_AsyncRun 失败: {}, {}\n", errcode, errs);
			logger->warn("Fix_AsyncRun 失败: {}, {}\n", errcode, errs);
			return false;
		}

		return true;
	}

	vector<map<int, string>> &&GetAnswers()
	{
		return std::move(m_Answers);
	}

private:
	string ParseError()
	{
		int code = Fix_GetLong(m_Session, FID_CODE, 0);
		if (code >= 0)
			return "";

		char errinfo[256]{};
		int len = sizeof(errinfo);
		return Fix_GetErrMsg(m_Session, errinfo, len);
	}

	bool SetDDParams()
	{
		string params;
		for (const auto &elem : *m_Params)
		{
			if (!Fix_SetItem(m_Session, elem.first, elem.second.c_str()))
			{
				fmt::print(fg(fmt::color::red), "Fix_SetItem[{},{}] 失败\n", elem.first, elem.second);
				return false;
			}
			params.append(fmt::format("({}:{})", elem.first, elem.second));
		}

		logger->info("[Request][{}]:{}", m_Funcid, params);

		return true;
	}

	void RecvAnswers(int recCount)
	{
		// auto ansIds = g_IndividualConfig.GetAnsIds(m_Funcid);

		char fieldVal[512]{};
		// int fieldLen = sizeof(fieldVal);
		// for (int index = 0; index < recCount; ++index)
		//{
		//	for (int fidId : ansIds)
		//	{
		//		Fix_GetItem(m_Session, fidId, fieldVal, fieldLen, index);
		//		oneAns.emplace(fidId, fieldVal);

		//		if (index == recCount - 1 && fidId == FID_BROWINDEX)
		//		{
		//			m_Params[FID_BROWINDEX] = fieldVal;
		//		}
		//	}

		//	if (!oneAns.empty())
		//		m_Answers.emplace_back(std::move(oneAns));
		//}

		for (int index = 0; index < recCount; ++index)
		{
			int col_count = Fix_GetColumnCount(m_Session, index);
			for (int col = 0; col < col_count; ++col)
			{
				int fidId = -1;

				int fieldLen = sizeof(fieldVal);
				::memset(fieldVal, 0, fieldLen);

				Fix_GetValWithIdByIndex(m_Session, index, col, fidId, fieldVal, fieldLen);

				oneAns.emplace(fidId, fieldVal);
				if (index == recCount - 1 && fidId == FID_BROWINDEX)
				{
					(*m_Params)[FID_BROWINDEX] = fieldVal;
				}
			}
			if (!oneAns.empty())
				m_Answers.emplace_back(std::move(oneAns));
		}

		for (const auto &rec : m_Answers)
		{
			string msg;
			for (const auto &[k, v] : rec)
			{
				msg.append(std::move(fmt::format("({}:{})", k, v)));
			}
			logger->info("[Response][{}]: {}", m_Funcid, msg);
		}
	}

	bool IsNeedNext(int recCount)
	{
		return false;

		if (recCount < 200)
			return false;

		return m_Params->find(FID_BROWINDEX) != m_Params->end();
	}

	HANDLE_SESSION m_Session = -1;
	unique_ptr<map<int, string>> m_Params;
	string m_Funcid;

	map<int, string> oneAns;
	vector<map<int, string>> m_Answers;
	HANDLE_CONN m_Conn;
};